package com.jsecode.diyview

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.View
import androidx.core.content.ContextCompat
import androidx.core.graphics.withRotation
import androidx.core.graphics.withTranslation
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import kotlinx.coroutines.*
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin

class MyView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr),LifecycleObserver {
    private var sineWaveSamplesPath = Path()
    private var rotatingJob : Job? = null
    private var mAngle = -10f
    private var mRadius = 0f
    private var mWidth = 0f;
    private var mHeight = 0f;
    private val filledCirclePaint = Paint().apply {
        style = Paint.Style.FILL
        color = ContextCompat.getColor(context,R.color.colorWhite)
    }
    private val filledCirclePaintRed = Paint().apply {
        style = Paint.Style.FILL
        color = ContextCompat.getColor(context,R.color.colorRed)
    }

    private val solidLinePaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 5f
        color = ContextCompat.getColor(context,R.color.colorWhite)
    }

    private val vectorLinePaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 5f
        color = ContextCompat.getColor(context,R.color.colorGreen)
    }

    private val textPaint = Paint().apply {
        textSize = 30f
        typeface = Typeface.DEFAULT_BOLD
        color = ContextCompat.getColor(context,R.color.colorWhite)
    }
    private val dashedLinePaint = Paint().apply {
        style = Paint.Style.STROKE
        pathEffect = DashPathEffect(floatArrayOf(10f,10f),0f)
        color = ContextCompat.getColor(context,R.color.colorYellow)
        strokeWidth = 5f
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mWidth = w.toFloat();
        mHeight = h.toFloat();
        mRadius = if(w < h /2) (w/2).toFloat() else (h/4).toFloat()
        mRadius -= 20f
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas?.apply {
            drawAxises(this)
            drawLable(this)
            drawDashedCircle(this)
            drawVector(this)
            drawProjections(this)
            drawSineWave(this)
        }
    }

    private fun  drawAxises(canvas: Canvas){
        canvas.withTranslation(mWidth /2,mHeight/2) {
            drawLine(-mWidth /2,0f,mWidth /2 ,0f,solidLinePaint)
            drawLine(0f,-mHeight /2,0f,mHeight /2,solidLinePaint)
        }
        canvas.withTranslation(mWidth /2,mHeight / 4 * 3) {
            drawLine(-mWidth/2,0f,mWidth/2,0f,solidLinePaint)
        }
    }

    private fun drawLable(canvas: Canvas){
        canvas.apply {
            drawRect(50f,50f,mWidth /2 - 50,150f,solidLinePaint)
            drawText("指数函数与旋转矢量",70f,110f,textPaint)
        }
    }

    private fun drawDashedCircle(canvas: Canvas){
        canvas.withTranslation(mWidth / 2,mHeight / 4 * 3) {
            drawCircle(0f,0f,mRadius,dashedLinePaint)
        }
    }

    private fun drawVector(canvas: Canvas){
        canvas.withTranslation(mWidth / 2,mHeight / 4 * 3) {
            withRotation(mAngle) {
                drawLine(0f,0f,mRadius,0f,vectorLinePaint)
            }
        }
    }

    private fun drawProjections(canvas: Canvas){
        canvas.withTranslation(mWidth/2,mHeight /2) {
            val cosAngle = cos(mAngle.toRadians()).toFloat()
            drawCircle(mRadius * cosAngle,0f,10f,filledCirclePaint)
        }
        canvas.withTranslation(mWidth/2,mHeight /4 * 3) {
            val cosAngle = Math.cos(mAngle.toRadians()).toFloat()
            drawCircle(mRadius * cosAngle,0f,10f,filledCirclePaint)
        }
        canvas.withTranslation(mWidth /2,mHeight /4 * 3) {
            val x = mRadius * cos(mAngle.toRadians()).toFloat();
            var y = mRadius * sin(mAngle.toRadians()).toFloat()
            withTranslation(x,y) {

                drawLine(0f,0f,0f,-mHeight/ 4 - y,dashedLinePaint)
                drawLine(0f,0f,0f,-y,solidLinePaint)
                //drawCircle(0f,0f,10f,filledCirclePaintRed)
            }
        }
    }

    private fun  drawSineWave(canvas: Canvas){
        canvas.withTranslation(mWidth/2,mHeight/2) {
            val sampleCount = 50;
            val dy = mHeight /2 / sampleCount;
            sineWaveSamplesPath.reset()
            sineWaveSamplesPath.moveTo(mRadius * cos(mAngle.toRadians().toFloat()),0f)
            repeat(sampleCount){
                val x = mRadius * cos(it * 0.15 +mAngle.toRadians().toFloat())
                val y = -dy * it
                sineWaveSamplesPath.quadTo(x.toFloat(),y,x.toFloat(),y)
            }
            drawPath(sineWaveSamplesPath,vectorLinePaint)
        }
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun startRotating(){
        rotatingJob = CoroutineScope(Dispatchers.Main).launch {
            while (true){
                delay(20);
                mAngle -= 1f
                invalidate()
            }
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun pauseRotating(){
        rotatingJob?.cancel()
    }

    private fun Float.toRadians() = this / 180 * PI
}